﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.Drawing;
using System.Collections;
using System.Windows.Forms.Design;

namespace NetJsWire.Design
{
    public class ControlDesigner : ComponentDesigner, IMessageReceiver
    {
        private WndProcRouter _messageRouter;
        private bool _locked = false;
        private bool _mouseDown = false;
        private bool _mouseDownFirstMove = false;
        private bool _firstMouseMoveInClient = true;

        public ControlDesigner()
        {
        }

        #region Initialization
        public override void Initialize( IComponent component )
        {
            base.Initialize( component );

            if ( !( component is Control ) )
                throw new ArgumentException( "Component is not a Control." );

            _messageRouter = new WndProcRouter( ( Control ) component, ( IMessageReceiver ) this );

            // DT properties
            //
            this.Visible = true;
            this.Enabled = true;
            this.Locked = false;
            this.AllowDrop = true;
            //
            // The control properties
            //
            Control.Enabled = true;
            Control.Visible = true;
            Control.AllowDrop = false;

            this.Control.DragDrop += new DragEventHandler( OnDragDrop );
            this.Control.DragEnter += new DragEventHandler( OnDragEnter );
            this.Control.DragLeave += new EventHandler( OnDragLeave );
            this.Control.DragOver += new DragEventHandler( OnDragOver );

            // XXX: The control already has a handle?
            //
            if ( Control.IsHandleCreated )
            {
                OnCreateHandle();
            }

            IUISelectionService uiSelectionServ = this.GetService( typeof( IUISelectionService ) ) as IUISelectionService;
            if ( uiSelectionServ == null )
            {
                IDesignerHost host = this.GetService( typeof( IDesignerHost ) ) as IDesignerHost;
                host.AddService( typeof( IUISelectionService ), new UISelectionService( host ) );
            }
        }

        public override void InitializeNonDefault()
        {
            base.InitializeNonDefault();
        }

        // The default implementation of this method sets the component's Text property to
        // its name (Component.Site.Name), if the property field is of type string.
        //
        public override void OnSetComponentDefaults()
        {
            if ( this.Component != null && this.Component.Site != null )
            {
                PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties( this.Component )[ "Text" ];
                if ( propertyDescriptor != null && !propertyDescriptor.IsReadOnly &&
                        propertyDescriptor.PropertyType == typeof( string ) )
                {
                    propertyDescriptor.SetValue( Component, Component.Site.Name );
                }
            }
        }
        #endregion


        #region Properties and Fields - AccessabilityObject Left
        protected static readonly Point InvalidPoint = new Point( int.MinValue, int.MinValue );

        public virtual Control Control
        {
            get { return ( Control ) base.Component; }
        }

        protected virtual bool EnableDragRect
        {
            get { return true; }
        }

        public virtual SelectionRules SelectionRules
        {
            get
            {
                if ( this.Control == null )
                    return SelectionRules.None;

                // all controls on the surface are visible
                //
                SelectionRules selectionRules = SelectionRules.Visible;

                if ( ( bool ) GetValue( this.Component, "Locked" ) == true )
                {
                    selectionRules |= SelectionRules.Locked;
                }
                else
                {
                    DockStyle dockStyle = ( DockStyle ) this.GetValue( base.Component, "Dock", typeof( DockStyle ) );

                    switch ( dockStyle )
                    {
                        case DockStyle.Top:
                            selectionRules |= SelectionRules.BottomSizeable;
                            break;
                        case DockStyle.Left:
                            selectionRules |= SelectionRules.RightSizeable;
                            break;
                        case DockStyle.Right:
                            selectionRules |= SelectionRules.LeftSizeable;
                            break;
                        case DockStyle.Bottom:
                            selectionRules |= SelectionRules.TopSizeable;
                            break;
                        case DockStyle.Fill:
                            break;
                        default:
                            selectionRules |= SelectionRules.Moveable;
                            selectionRules |= SelectionRules.AllSizeable;
                            break;
                    }
                }

                return selectionRules;
            }
        }

        public override ICollection AssociatedComponents
        {
            get
            {
                ArrayList components = new ArrayList();
                foreach ( Control c in this.Control.Controls )
                    if ( c.Site != null )
                        components.Add( c );
                return components;
            }
        }

        protected override IComponent ParentComponent
        {
            get { return this.GetValue( this.Control, "Parent" ) as Control; }
        }

        // TODO: implement ControlDesigner.ControlAccessabilityObject
        //
        public virtual AccessibleObject AccessibilityObject
        {
            get
            {
                if ( accessibilityObj == null )
                    accessibilityObj = new AccessibleObject();

                return accessibilityObj;
            }
        }
        protected AccessibleObject accessibilityObj;

        #endregion


        #region WndProc

        protected void DefWndProc( ref Message m )
        {
            _messageRouter.ToControl( ref m );
        }

        protected void BaseWndProc( ref Message m )
        {
            _messageRouter.ToSystem( ref m );
        }

        void IMessageReceiver.WndProc( ref Message m )
        {
            this.WndProc( ref m );
        }

        // Keep in mind that messages are recieved for the child controls if routed
        //
        protected virtual void WndProc( ref Message m )
        {
            // Filter out kb input
            //
            if ( ( Native.Msg ) m.Msg >= Native.Msg.WM_KEYFIRST && ( Native.Msg ) m.Msg <= Native.Msg.WM_KEYLAST )
                return;

            // Mouse messages should be routed the control, if GetHitTest (virtual) returns true.
            //
            if ( IsMouseMessage( ( Native.Msg ) m.Msg ) &&
                            this.GetHitTest( new Point( Native.LoWord( ( int ) m.LParam ), Native.HiWord( ( ( int ) m.LParam ) ) ) ) )
            {

                this.DefWndProc( ref m );
                return;
            }

            switch ( ( Native.Msg ) m.Msg )
            {
                case Native.Msg.WM_CREATE:
                    this.DefWndProc( ref m );
                    if ( m.HWnd == this.Control.Handle )
                        OnCreateHandle();
                    break;

                case Native.Msg.WM_CONTEXTMENU:
                    OnContextMenu( Native.LoWord( ( int ) m.LParam ), Native.HiWord( ( int ) m.LParam ) );
                    break;

                case Native.Msg.WM_SETCURSOR:
                    if ( this.GetHitTest( new Point( Native.LoWord( ( int ) m.LParam ), Native.HiWord( ( int ) m.LParam ) ) ) )
                        this.DefWndProc( ref m );
                    else
                        OnSetCursor();
                    break;

                case Native.Msg.WM_SETFOCUS:
                    this.DefWndProc( ref m );
                    break;

                case Native.Msg.WM_PAINT:
                    // Wait for control's WM_PAINT to complete first.
                    //
                    this.DefWndProc( ref m );

                    Graphics gfx = Graphics.FromHwnd( m.HWnd );
                    PaintEventArgs args = new PaintEventArgs( gfx, this.Control.Bounds );
                    OnPaintAdornments( args );
                    gfx.Dispose();
                    args.Dispose();
                    break;

                case Native.Msg.WM_NCRBUTTONDOWN:
                case Native.Msg.WM_NCMBUTTONDOWN:
                case Native.Msg.WM_NCLBUTTONDBLCLK:
                case Native.Msg.WM_NCRBUTTONDBLCLK:
                    break;

                case Native.Msg.WM_LBUTTONDBLCLK:
                case Native.Msg.WM_RBUTTONDBLCLK:
                case Native.Msg.WM_MBUTTONDBLCLK:
                    if ( ( Native.Msg ) m.Msg == Native.Msg.WM_LBUTTONDBLCLK )
                        _mouseButtonDown = MouseButtons.Left;
                    else if ( ( Native.Msg ) m.Msg == Native.Msg.WM_RBUTTONDBLCLK )
                        _mouseButtonDown = MouseButtons.Right;
                    else if ( ( Native.Msg ) m.Msg == Native.Msg.WM_MBUTTONDBLCLK )
                        _mouseButtonDown = MouseButtons.Middle;
                    OnMouseDoubleClick();
                    this.BaseWndProc( ref m );
                    break;

                case Native.Msg.WM_MOUSEHOVER:
                    OnMouseHover();
                    break;

                case Native.Msg.WM_LBUTTONDOWN:
                case Native.Msg.WM_RBUTTONDOWN:
                case Native.Msg.WM_MBUTTONDOWN:
                    if ( ( Native.Msg ) m.Msg == Native.Msg.WM_LBUTTONDOWN )
                        _mouseButtonDown = MouseButtons.Left;
                    else if ( ( Native.Msg ) m.Msg == Native.Msg.WM_RBUTTONDOWN )
                        _mouseButtonDown = MouseButtons.Right;
                    else if ( ( Native.Msg ) m.Msg == Native.Msg.WM_MBUTTONDOWN )
                        _mouseButtonDown = MouseButtons.Middle;

                    if ( _firstMouseMoveInClient )
                    {
                        OnMouseEnter();
                        _firstMouseMoveInClient = false;
                    }
                    this.OnMouseDown( Native.LoWord( ( int ) m.LParam ), Native.HiWord( ( int ) m.LParam ) );
                    this.BaseWndProc( ref m );
                    break;

                case Native.Msg.WM_MOUSELEAVE:
                    _firstMouseMoveInClient = false;
                    OnMouseLeave();
                    this.BaseWndProc( ref m );
                    break;

                // The WM_CANCELMODE message is sent to cancel certain modes, such as mouse capture.
                // For example, the system sends this message to the active window when a dialog box
                // or message box is displayed. Certain functions also send this message explicitly to
                // the specified window regardless of whether it is the active window. For example,
                // the EnableWindow function sends this message when disabling the specified window.
                //
                case Native.Msg.WM_CANCELMODE:
                    OnMouseDragEnd( true );
                    this.DefWndProc( ref m );
                    break;

                case Native.Msg.WM_LBUTTONUP:
                case Native.Msg.WM_RBUTTONUP:
                case Native.Msg.WM_NCLBUTTONUP:
                case Native.Msg.WM_NCRBUTTONUP:
                case Native.Msg.WM_MBUTTONUP:
                case Native.Msg.WM_NCMBUTTONUP:
                    this.OnMouseUp();
                    this.BaseWndProc( ref m );
                    break;

                // MWF Specific msg! - must reach control
                //
                case Native.Msg.WM_MOUSE_ENTER:
                    _firstMouseMoveInClient = false; // just so that nothing will get fired in WM_MOUSEMOVE
                    OnMouseEnter();
                    this.DefWndProc( ref m );
                    break;

                case Native.Msg.WM_MOUSEMOVE:
                    // If selection is in progress pass the mouse move msg to the primary selection.
                    // If resizing is in progress pass to the parent of the primary selection (remmember that the selection
                    // frame is not a control and is drawn in the parent of the primary selection).
                    //
                    // Required in order for those 2 operations to continue when the mouse is moving over a control covering
                    // the one where the action takes place.
                    //
                    IUISelectionService uiSelectionServ = this.GetService( typeof( IUISelectionService ) ) as IUISelectionService;
                    ISelectionService selectionServ = this.GetService( typeof( ISelectionService ) ) as ISelectionService;
                    IDesignerHost host = this.GetService( typeof( IDesignerHost ) ) as IDesignerHost;


                    if ( uiSelectionServ != null && selectionServ != null && host != null )
                    {
                        Control primarySelection = selectionServ.PrimarySelection as Control;
                        Point location = new Point( Native.LoWord( ( int ) m.LParam ), Native.HiWord( ( int ) m.LParam ) );

                        if ( uiSelectionServ.SelectionInProgress &&
                                this.Component != host.RootComponent &&
                                this.Component != selectionServ.PrimarySelection )
                        {

                            location = primarySelection.PointToClient( this.Control.PointToScreen( location ) );
                            Native.SendMessage( primarySelection.Handle, ( Native.Msg ) m.Msg, m.WParam, Native.LParam( location.X, location.Y ) );
                        }
                        else if ( uiSelectionServ.ResizeInProgress &&
                            // this.Component != host.RootComponent &&
                                this.Control.Parent == ( ( Control ) selectionServ.PrimarySelection ).Parent )
                        {

                            location = this.Control.Parent.PointToClient( this.Control.PointToScreen( location ) );
                            Native.SendMessage( this.Control.Parent.Handle, ( Native.Msg ) m.Msg, m.WParam, Native.LParam( location.X, location.Y ) );
                        }
                        else
                        {
                            this.OnMouseMove( location.X, location.Y );
                        }
                    }
                    else
                    {
                        this.OnMouseMove( Native.LoWord( ( int ) m.LParam ), Native.HiWord( ( int ) m.LParam ) );
                    }
                    this.BaseWndProc( ref m );
                    break;

                default:
                    // Pass everything else to the control and return
                    //
                    this.DefWndProc( ref m );
                    break;
            }
        }

        // Indicates whether a mouse click at the specified point should be handled by the control.
        //
        protected virtual bool GetHitTest( Point point )
        {
            return false;
        }

        private bool IsMouseMessage( Native.Msg msg )
        {
            if ( msg >= Native.Msg.WM_MOUSEFIRST && msg <= Native.Msg.WM_MOUSELAST )
                return true;
            else if ( msg >= Native.Msg.WM_NCLBUTTONDOWN && msg <= Native.Msg.WM_NCMBUTTONDBLCLK )
                return true;
            else if ( msg == Native.Msg.WM_MOUSEHOVER || msg == Native.Msg.WM_MOUSELEAVE )
                return true;
            else
                return false;
        }
        #endregion


        #region WndProc Message Handlers

        protected virtual void OnSetCursor()
        {
        }

        // Raises the DoDefaultAction.
        //
        private void OnMouseDoubleClick()
        {
            try
            {
                base.DoDefaultAction();
            }
            catch ( Exception e )
            {
                this.DisplayError( e );
            }
        }

        internal virtual void OnMouseDown( int x, int y )
        {
            _mouseDown = true;
            _mouseDownFirstMove = true;
            IUISelectionService uiSelection = this.GetService( typeof( IUISelectionService ) ) as IUISelectionService;
            if ( uiSelection != null && uiSelection.AdornmentsHitTest( this.Control, x, y ) )
            {
                // 1) prevent primary selection from being changed at this point.
                // 2) delegate behaviour in the future to the IUISelectionService
            }
            else
            {
                ISelectionService selectionService = this.GetService( typeof( ISelectionService ) ) as ISelectionService;
                if ( selectionService != null )
                {
                    selectionService.SetSelectedComponents( new IComponent[] { this.Component } );
                }
            }
        }

        // Note that this is a pure WM_MOUSEMOVE acceptor
        //
        internal virtual void OnMouseMove( int x, int y )
        {
            // Fire the OnMouseEnter if this is the first mousemove in
            // the client area. (I have to, because there is no WM_MOUSEENTER msg)
            //
            if ( _mouseDown )
            {
                if ( _mouseDownFirstMove )
                {
                    OnMouseDragBegin( x, y );
                    _mouseDownFirstMove = false;
                }
                else
                {
                    OnMouseDragMove( x, y );
                }
            }

        }

        internal virtual void OnMouseUp()
        {
            IUISelectionService uiSelection = this.GetService( typeof( IUISelectionService ) ) as IUISelectionService;

            if ( _mouseDown )
            {
                if ( uiSelection != null && ( uiSelection.SelectionInProgress || uiSelection.ResizeInProgress ) )
                {
                    uiSelection.MouseDragEnd( false );
                }
                this.OnMouseDragEnd( false );
                _mouseDown = false;
            }
            else
            {
                if ( uiSelection != null && ( uiSelection.SelectionInProgress || uiSelection.ResizeInProgress ) )
                {
                    // If the mouse up happens over the a control which is not defacto participating in
                    // the selection or resizing in progress, then inform the IUISelectionService of that event
                    //
                    uiSelection.MouseDragEnd( false );
                }
            }
        }

        protected virtual void OnContextMenu( int x, int y )
        {
            IMenuCommandService service = this.GetService( typeof( IMenuCommandService ) ) as IMenuCommandService;
            if ( service != null )
            {
                service.ShowContextMenu( MenuCommands.SelectionMenu, x, y );
            }
        }

        protected virtual void OnMouseEnter()
        {
        }

        protected virtual void OnMouseHover()
        {
        }

        protected virtual void OnMouseLeave()
        {
        }

        // Provides an opportunity to perform additional processing immediately
        // after the control handle has been created.
        //
        protected virtual void OnCreateHandle()
        {
        }

        // Called after the control is done with the painting so that the designer host
        // can paint stuff over it.
        //
        protected virtual void OnPaintAdornments( PaintEventArgs pe )
        {
        }
        #endregion


        #region Mouse Dragging

        MouseButtons _mouseButtonDown;

        internal MouseButtons MouseButtonDown
        {
            get { return _mouseButtonDown; }
        }

        protected virtual void OnMouseDragBegin( int x, int y )
        {
            IUISelectionService selectionServ = this.GetService( typeof( IUISelectionService ) ) as IUISelectionService;
            if ( selectionServ != null && ( ( this.SelectionRules & SelectionRules.Moveable ) == SelectionRules.Moveable ) )
            {
                // once this is fired the parent control (parentcontroldesigner) will start getting dragover events.
                //
                selectionServ.DragBegin();
            }
        }

        protected virtual void OnMouseDragMove( int x, int y )
        {
            IUISelectionService selectionServ = this.GetService( typeof( IUISelectionService ) ) as IUISelectionService;
            if ( selectionServ != null && ( ( this.SelectionRules & SelectionRules.Moveable ) == SelectionRules.Moveable ) )
            {
                // once this is fired the parent control (parentcontroldesigner) will start getting dragover events.
                //
                selectionServ.MouseDragMove( x, y );
            }
        }

        protected virtual void OnMouseDragEnd( bool cancel )
        {
            IUISelectionService selectionServ = this.GetService( typeof( IUISelectionService ) ) as IUISelectionService;
            if ( selectionServ != null && ( ( this.SelectionRules & SelectionRules.Moveable ) == SelectionRules.Moveable ) )
            {
                // once this is fired the parent control (parentcontroldesigner) will start getting dragover events.
                //
                selectionServ.MouseDragEnd( cancel );
            }
        }
        #endregion


        #region Parenting
        protected void HookChildControls( Control firstControl )
        {
            if ( firstControl != null )
            {
                foreach ( Control control in firstControl.Controls )
                    new WndProcRouter( control, ( IMessageReceiver ) this );
            }
        }

        protected void UnHookChildControls( Control firstControl )
        {
            if ( firstControl != null )
            {
                foreach ( Control control in firstControl.Controls )
                {
                    if ( control.WindowTarget is WndProcRouter )
                        ( ( WndProcRouter ) control.WindowTarget ).Dispose();
                }
            }
        }

        // Someone please tell me why the hell is this method here?
        // What about having ParentControlDesigner.CanParent(...) ?
        //
        public virtual bool CanBeParentedTo( IDesigner parentDesigner )
        {
            IDesignerHost host = this.GetService( typeof( IDesignerHost ) ) as IDesignerHost;

            if ( parentDesigner is ParentControlDesigner &&
                    this.Component != host.RootComponent &&
                    !this.Control.Controls.Contains( ( ( ParentControlDesigner ) parentDesigner ).Control ) )
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion

        protected void DisplayError( Exception e )
        {
            if ( e != null )
            {
                IUIService uiService = GetService( typeof( IUIService ) ) as IUIService;
                if ( uiService != null )
                {
                    uiService.ShowError( e );
                }
                else
                {
                    string errorText = e.Message;
                    if ( errorText == null || errorText == String.Empty )
                        errorText = e.ToString();
                    MessageBox.Show( Control, errorText, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation );
                }
            }
        }

        #region Drag and Drop handling

        // Enables or disables Drag and Drop
        //
        protected void EnableDragDrop( bool value )
        {
            if ( this.Control != null )
            {
                if ( value )
                {
                    Control.DragDrop += new DragEventHandler( OnDragDrop );
                    Control.DragOver += new DragEventHandler( OnDragOver );
                    Control.DragEnter += new DragEventHandler( OnDragEnter );
                    Control.DragLeave += new EventHandler( OnDragLeave );
                    Control.GiveFeedback += new GiveFeedbackEventHandler( OnGiveFeedback );
                    Control.AllowDrop = true;
                }
                else
                {
                    Control.DragDrop -= new DragEventHandler( OnDragDrop );
                    Control.DragOver -= new DragEventHandler( OnDragOver );
                    Control.DragEnter -= new DragEventHandler( OnDragEnter );
                    Control.DragLeave -= new EventHandler( OnDragLeave );
                    Control.GiveFeedback -= new GiveFeedbackEventHandler( OnGiveFeedback );
                    Control.AllowDrop = false;
                }
            }
        }

        private void OnGiveFeedback( object sender, GiveFeedbackEventArgs e )
        {
            OnGiveFeedback( e );
        }

        private void OnDragDrop( object sender, DragEventArgs e )
        {
            OnDragDrop( e );
        }

        private void OnDragEnter( object sender, DragEventArgs e )
        {
            OnDragEnter( e );
        }

        private void OnDragLeave( object sender, EventArgs e )
        {
            OnDragLeave( e );
        }

        private void OnDragOver( object sender, DragEventArgs e )
        {
            OnDragOver( e );
        }

        protected virtual void OnGiveFeedback( GiveFeedbackEventArgs e )
        {
            e.UseDefaultCursors = false;
        }

        protected virtual void OnDragDrop( DragEventArgs e )
        {
        }

        protected virtual void OnDragEnter( DragEventArgs e )
        {
        }

        protected virtual void OnDragLeave( EventArgs e )
        {
        }

        protected virtual void OnDragOver( DragEventArgs e )
        {
        }
        #endregion


        #region Redirected Properties

        // This IDesignerFilter interface method override adds a set of properties
        // to this designer's component at design time. This method adds the following
        // browsable properties: "Visible", "Enabled", "ContextMenu", "AllowDrop", "Location",
        // "Name", "Controls", and "Locked".
        //
        // XXX: We aren't redirecting Controls
        //
        protected override void PreFilterProperties( IDictionary properties )
        {
            base.PreFilterProperties( properties );

            string[] newProperties = {
                                "Visible", "Enabled", "ContextMenu", "AllowDrop", "Location", "Name",
                        };

            Attribute[][] attributes = {
                                new Attribute[] { new DefaultValueAttribute (true) },
                                new Attribute[] { new DefaultValueAttribute (true) },
                                new Attribute[] { new DefaultValueAttribute (null) },
                                new Attribute[] { new DefaultValueAttribute (false) },
                                new Attribute[] { new DefaultValueAttribute (typeof (Point), "0, 0") },
                                new Attribute[] {}
                         };

            PropertyDescriptor propertyDescriptor = null;

            // If existing redirect each property to the ControlDesigner.
            //
            for ( int i = 0; i < newProperties.Length; i++ )
            {
                propertyDescriptor = properties[ newProperties[ i ] ] as PropertyDescriptor;
                if ( propertyDescriptor != null )
                    properties[ newProperties[ i ] ] = TypeDescriptor.CreateProperty( typeof( ControlDesigner ),
                                                                                                                                              propertyDescriptor,
                                                                                                                                              attributes[ i ] );
            }

            // This one is a must to have.
            //
            properties[ "Locked" ] = TypeDescriptor.CreateProperty( typeof( ControlDesigner ), "Locked",
                                                                      typeof( bool ),
                                                                      new Attribute[] {
                                                                                          DesignOnlyAttribute.Yes,
                                                                                          BrowsableAttribute.Yes,
                                                                                          CategoryAttribute.Design,
                                                                                          new DefaultValueAttribute (false),
                                                                                          new DescriptionAttribute("The Locked property determines if we can move or resize the control.")
                                                                                  } );

        }

        // ShadowProperties returns the real property value if there is no "shadow" one set
        // Welcome to the land of shadows... :-)
        //
        private bool Visible
        {
            get { return ( bool ) base.ShadowProperties[ "Visible" ]; }
            set { base.ShadowProperties[ "Visible" ] = value; }
        }

        private bool Enabled
        {
            get { return ( bool ) base.ShadowProperties[ "Enabled" ]; }
            set { base.ShadowProperties[ "Enabled" ] = value; }
        }

        private bool Locked
        {
            get { return _locked; }
            set { _locked = value; }
        }

        private bool AllowDrop
        {
            get { return ( bool ) base.ShadowProperties[ "AllowDrop" ]; }
            set { base.ShadowProperties[ "AllowDrop" ] = value; }
        }

        private string Name
        {
            get { return base.Component.Site.Name; }
            set
            {
                if ( value != null )
                    base.Component.Site.Name = value;
            }
        }

        private ContextMenu ContextMenu
        {
            get { return ( ContextMenu ) base.ShadowProperties[ "ContextMenu" ]; }
            set { base.ShadowProperties[ "ContextMenu" ] = value; }
        }

        private Point Location
        {
            get { return this.Control.Location; }
            set { this.Control.Location = value; }
        }
        #endregion


        #region Utility methods
        internal object GetValue( object component, string propertyName )
        {
            return this.GetValue( component, propertyName, null );
        }

        internal object GetValue( object component, string propertyName, Type propertyType )
        {
            PropertyDescriptor prop = TypeDescriptor.GetProperties( component )[ propertyName ] as PropertyDescriptor;
            if ( prop == null )
                throw new InvalidOperationException( "Property \"" + propertyName + "\" is missing on " +
                                                                                         component.GetType().AssemblyQualifiedName );
            if ( propertyType != null && !propertyType.IsAssignableFrom( prop.PropertyType ) )
                throw new InvalidOperationException( "Types do not match: " + prop.PropertyType.AssemblyQualifiedName +
                                                                                         " : " + propertyType.AssemblyQualifiedName );
            return prop.GetValue( component );
        }

        public void SetValue( object component, string propertyName, object value )
        {
            PropertyDescriptor prop = TypeDescriptor.GetProperties( component )[ propertyName ] as PropertyDescriptor;

            if ( prop == null )
                throw new InvalidOperationException( "Property \"" + propertyName + "\" is missing on " +
                                                                                         component.GetType().AssemblyQualifiedName );
            if ( !prop.PropertyType.IsAssignableFrom( value.GetType() ) )
                throw new InvalidOperationException( "Types do not match: " + value.GetType().AssemblyQualifiedName +
                                                                                         " : " + prop.PropertyType.AssemblyQualifiedName );
            if ( !prop.IsReadOnly )
                prop.SetValue( component, value );
        }
        #endregion

        protected override void Dispose( bool disposing )
        {
            if ( disposing )
            {
                if ( this.Control != null )
                {
                    UnHookChildControls( Control );
                    OnMouseDragEnd( true );
                    _messageRouter.Dispose();
                    this.Control.DragDrop -= new DragEventHandler( OnDragDrop );
                    this.Control.DragEnter -= new DragEventHandler( OnDragEnter );
                    this.Control.DragLeave -= new EventHandler( OnDragLeave );
                    this.Control.DragOver -= new DragEventHandler( OnDragOver );
                }
            }
            base.Dispose( true );
        }



#if !Blah
        public virtual ControlDesigner InternalControlDesigner( int internalControlIndex )
        {
            return null;
        }

        public virtual int NumberOfInternalControlDesigners()
        {
            return 0;
        }

        protected bool EnableDesignMode( Control child, string name )
        {
            if ( name == null )
                throw new ArgumentNullException( "name" );
            if ( child == null )
                throw new ArgumentNullException( "child" );

            bool success = false;
            INestedContainer nestedContainer = this.GetService( typeof( INestedContainer ) ) as INestedContainer;
            if ( nestedContainer != null )
            {
                nestedContainer.Add( child, name );
                success = true;
            }
            return success;
        }

        #region NET_2_0 Stubs

        /*
                protected virtual ControlBodyGlyph GetControlGlyph (GlyphSelectionType selectionType)
                {
                        throw new NotImplementedException ();
                }

                public virtual GlyphCollection GetGlyphs (GlyphSelectionType selectionType)
                {
                        throw new NotImplementedException ();
                }
                */

        public override void InitializeExistingComponent( IDictionary defaultValues )
        {
            throw new NotImplementedException();
        }

        public override void InitializeNewComponent( IDictionary defaultValues )
        {
            var props = TypeDescriptor.GetProperties( Component );
            foreach ( PropertyDescriptor prop in props )
            {
                if ( defaultValues[ prop.Name ] != null )
                {
                    prop.SetValue( Component, defaultValues[ prop.Name ] );
                }
            }
            //throw new NotImplementedException();
        }

        protected virtual void OnDragComplete( DragEventArgs de )
        {
            throw new NotImplementedException();
        }

        public virtual IList SnapLines
        {
            get { throw new NotImplementedException(); }
        }

        /*
        protected BehaviorService BehaviorService {
                get { throw new NotImplementedException (); }
        }
        */

        public virtual bool ParticipatesWithSnapLines
        {
            get { throw new NotImplementedException(); }
        }

        public bool AutoResizeHandles
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }
        #endregion
#endif


    }
}